package com.yami.shop.platform.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yami.shop.bean.bo.ProductBO;
import com.yami.shop.bean.enums.EsOperationType;
import com.yami.shop.bean.enums.ProdStatusEnums;
import com.yami.shop.bean.enums.ProdType;
import com.yami.shop.bean.event.EsProductUpdateEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.EsProductParam;
import com.yami.shop.bean.vo.search.ProductSearchVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.util.DataWebService;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.mystery.common.dto.ActivityProdDto;
import com.yami.shop.mystery.common.model.MysteryBox;
import com.yami.shop.mystery.common.service.ActivityPresellService;
import com.yami.shop.mystery.common.service.MysteryBoxService;
import com.yami.shop.search.common.service.SearchProductService;
import com.yami.shop.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author yami
 */
@Component
public class ProdTask {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ProductService productService;
    @Autowired
    private ProdNftService prodNftService;
    @Autowired
    private ProdLangService prodLangService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ActivityPresellService activityPresellService;

    @Autowired
    private SearchProductService searchProductService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;;
    @Autowired
    private ShopDetailService shopDetailService;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private DataWebService dataWebService;
    @Autowired
    private ShopSynchronizationDataService shopSynchronizationDataService;

    @Autowired
    private BlockchainShopService blockchainShopService;

    @Autowired
    private MysteryBoxService mysteryBoxService;


    @XxlJob("recoveryPreSaleProd")
    public void recoveryPreSaleProd(){
        logger.info("过了预售时间的商品，恢复成普通商品状态。。。");
        // 获取30分钟之前未支付的订单
        List<Product> products = productService.recoveryPreSaleProd();
        if(CollectionUtils.isEmpty(products)){
            return;
        }
        for (Product product : products) {
            //清除缓存
            productService.removeProdCacheByProdId(product.getProdId());
        }
    }

    @XxlJob("offlineExpireVirtualProd")
    public void offlineExpireVirtualProd(){
        logger.info("过了核销时间的虚拟商品，进行下架操作。");
        // 获取30分钟之前未支付的订单
        List<Product> products = productService.handleExpireVirtualProd();
        if(CollectionUtils.isEmpty(products)){
            return;
        }
        List<Long> ids = new ArrayList<>();
        for (Product product : products) {
            //清除缓存
            productService.removeProdCacheByProdId(product.getProdId());
            ids.add(product.getProdId());
        }
        applicationContext.publishEvent(new EsProductUpdateEvent(null, ids, EsOperationType.UPDATE_BATCH));
    }
    /**
     * 校验商品数量是否完整
     * 商品数据是否为最新的：根据商品更新时间判断
     */
    @XxlJob("verifyProdStockAndSold")
    public void verifySpuStockAndSold(){
        // 获取6分钟内提交订单中的商品列表
        List<Long> prodIds = orderMapper.listProdIdByTime(DateUtil.offsetDay(new Date(), -6));
        if (CollUtil.isEmpty(prodIds)) {
            return;
        }

        // 从es中查询商品的库存和销量数据
        EsProductParam productParam = new EsProductParam();
        productParam.setProdIds(prodIds);
        productParam.setFetchSource(new String[]{"prodId", "totalStocks", "soldNum", "actualSoldNum"});
        List<ProductSearchVO> esProdList = searchProductService.listSpuByProdIds(productParam);
        Map<Long, ProductSearchVO> prodMap = esProdList.stream().collect(Collectors.toMap(ProductSearchVO::getProdId, p -> p));


        // 从mysql中查询商品的库存和销量数据
        List<ProductBO> prodList = productService.listProdStockAndSold(prodIds);
        List<Long> updateList = new ArrayList<>();
        //比较es和mysql的商品数据
        for (ProductBO productBO : prodList) {
            ProductSearchVO productSearchVO = prodMap.get(productBO.getProdId());
            if (Objects.isNull(productSearchVO)) {
                continue;
            }
            boolean change = !Objects.equals(productBO.getTotalStocks(),  productSearchVO.getTotalStocks()) ||
                    !Objects.equals(productBO.getActualSoldNum() + productBO.getWaterSoldNum(), productSearchVO.getSoldNum()) ||
                    !Objects.equals(productBO.getActualSoldNum(), productSearchVO.getActualSoldNum());
            if (change) {
                updateList.add(productBO.getProdId());
            }
        }
        // 数据不一致的商品，更新es中的数据
        if (CollUtil.isNotEmpty(updateList)) {
            eventPublisher.publishEvent(new EsProductUpdateEvent(null, updateList, EsOperationType.UPDATE_SOLD_NUM_BATCH));
        }
    }



//    @XxlJob("prodPutaway")
    public void prodPutaway(){
        logger.info("过了上架时间的商品，商品状态改为上架");
        // 获取超过上架时间的商品信息
        List<ActivityProdDto> prodIds = activityPresellService.getPutawayProdId();
        if(CollectionUtils.isEmpty(prodIds)){
            logger.info("活动下没有要上架的商品");
            return;
        }

        List<Long> prods = prodIds.stream().filter(a -> a.getBlindType() == 0 && a.getProdId() != -1).map(ActivityProdDto::getProdId).collect(Collectors.toList());
        List<Long> boxs = prodIds.stream().filter(a -> a.getBlindType() == 1 && a.getProdId() != -1).map(ActivityProdDto::getProdId).collect(Collectors.toList());

        if(CollectionUtils.isNotEmpty(prods)){
            QueryWrapper<Product> productQueryWrapper = new QueryWrapper<>();
            productQueryWrapper.select("prod_id");
            productQueryWrapper.in("prod_id",prods);
            productQueryWrapper.eq("status",9);
            List<Product> products = productService.list(productQueryWrapper);
            if(CollectionUtils.isNotEmpty(products)){
                List<Long> updateList = products.stream().map(Product::getProdId).collect(Collectors.toList());
                productService.changeStatusByProdIds(updateList, ProdStatusEnums.NORMAL.getValue());
                for (Product product : products) {
                    //清除缓存
                    productService.removeProdCacheByProdId(product.getProdId());
                    // 修改ES数据
                    eventPublisher.publishEvent(new EsProductUpdateEvent(product.getProdId(), null, EsOperationType.UPDATE));
                }
            }

        }

        if(CollectionUtils.isNotEmpty(boxs)){
            QueryWrapper<MysteryBox> productQueryWrapper = new QueryWrapper<>();
            productQueryWrapper.select("id");
            productQueryWrapper.in("id",boxs);
            productQueryWrapper.eq("status",9);
            List<MysteryBox> mysteryBoxes = mysteryBoxService.list(productQueryWrapper);
            if(CollectionUtils.isNotEmpty(mysteryBoxes)){
                for (MysteryBox product : mysteryBoxes) {
                    mysteryBoxService.mysteryBoxStatus(product.getId(), ProdStatusEnums.NORMAL.getValue());
                }
            }
        }
    }

    /**
     * 功能描述: 同步下游商品信息
     * @Author: LSR
     * @Date: 2023/4/3 15:03
     */
    @XxlJob("synchronizationProdData")
    public void synchronizationProdData() {
        // 获取开启同步信息的商户
        List<BlockchainShop> list = blockchainShopService.list(Wrappers.lambdaQuery(BlockchainShop.class).in(BlockchainShop::getIsSynchronization, 1,2));
        for (BlockchainShop shop : list) {
            ShopDetail shopDetail = shopDetailService.getById(shop.getShopId());
            if (null == shopDetail) {
                continue;
            }
            synchronizationChannelProduct(shop, shopDetail);
        }
    }

    /**
     *  同步某一渠道某一链的商品信息
     *
     * @param shop       dtc++平台商品链配置对象
     * @param shopDetail 下游渠道
     */
    public void synchronizationChannelProduct(BlockchainShop shop, ShopDetail shopDetail) {

        // 获取该商户下游商品信息
        Map<String, String> stringObjectMap1 = new HashMap<>();
        stringObjectMap1.put("channelCode", shopDetail.getChannelCode());
        stringObjectMap1.put("chain", shop.getBlockchainCode());
        stringObjectMap1.put("isSynchronization", String.valueOf( shop.getIsSynchronization()));
        String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/prodInfo/synchronizationAllProdData?";
        List<Product> prodInfoList = new ArrayList<>();
        try {
            JSONObject jsonObject = dataWebService.hutoolGetWebService(url, stringObjectMap1,shopDetail.getApiUser(),shopDetail.getApiPassword());
            if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
                logger.info("同步商品异常{}",jsonObject.getString("msg"));
                return;
            }
            prodInfoList = JSONObject.parseArray(jsonObject.getJSONArray("data").toJSONString(),Product.class);
        } catch (Exception e) {
            return;
        }

        //执行过就修改同步状态为2
        if (shop.getIsSynchronization() == 1) {
            blockchainShopService.update(Wrappers.lambdaUpdate(BlockchainShop.class)
                    .set(BlockchainShop::getIsSynchronization, 2).eq(BlockchainShop::getBlockchainShopId, shop.getBlockchainShopId()));
        }
        // 获取DTC++ 商品信息
        if(ObjectUtil.isEmpty(prodInfoList)){
            return;
        }

        List<Product> synchronizationprodList = productService.getSynchronizationprodList(1L,shop.getShopId());
        // 商品信息匹对
        List<Long> collect = synchronizationprodList.stream().map(Product::getSourceId).collect(Collectors.toList());
        // 需要新增的商品信息
        List<Product> addProdData = prodInfoList.stream().filter(s -> !collect.contains(s.getProdId())).collect(Collectors.toList());
        List<Product> updateProdData = new ArrayList<>();
        if(ObjectUtil.isNotEmpty(addProdData)){
            prodInfoList.removeAll(addProdData);
            for(Product product : addProdData){
                product.setSourceId(product.getProdId());
                product.setSource(1);
                product.setProdId(null);
                product.setShopId(shop.getShopId());
                product.setChain(shop.getBlockchainCode());
                product.setChannelCode(shop.getShopCode());
                product.setDeliveryTemplateId(-1L);
                productService.save(product);
                // 保存语言表信息
                List<ProdLang> prodLangList = new ArrayList<>();
                ProdLang prodLang = new ProdLang();
                prodLang.setProdId(product.getProdId());
                prodLang.setLang(0);
                prodLang.setBrief(product.getBrief());
                prodLang.setContent(product.getContent());
                prodLang.setProdName(product.getProdName());
                prodLangList.add(prodLang);
                prodLangService.saveBatch(prodLangList);

                if(!Objects.isNull(product.getMold()) && Objects.equals(product.getMold(), ProdType.PROD_TYPE_SECKILL.value())) {
                    ProdNft prodNft = BeanUtil.copyProperties(product.getVirtualProductForm(), ProdNft.class);
                    prodNft.setProdId(product.getProdId());
                    prodNftService.save(prodNft);
                }
            }
        }
        // 需要匹配的商品信息
        for (Product product : prodInfoList){
            Product synchronizationprodProduct = synchronizationprodList.stream().filter(s -> s.getSourceId().longValue() == product.getProdId().longValue()).findFirst().get();
            boolean isSynchronizationprod = matchingProdData(product,synchronizationprodProduct);
            if(isSynchronizationprod){
                product.setSourceId(product.getProdId());
                product.setSource(1);
                product.setProdId(synchronizationprodProduct.getProdId());
                product.setShopId(shop.getShopId());
                product.setChain(shop.getBlockchainCode());
                product.setChannelCode(shop.getShopCode());
                product.setVersion(synchronizationprodProduct.getVersion());
                updateProdData.add(product);
                productService.updateById(product);
                // 删除商品对应语言信息列表
                prodLangService.remove(new LambdaQueryWrapper<ProdLang>().eq(ProdLang::getProdId, product.getProdId()));
                // 保存语言表信息
                List<ProdLang> prodLangList = new ArrayList<>();
                ProdLang prodLang = new ProdLang();
                prodLang.setProdId(product.getProdId());
                prodLang.setLang(0);
                prodLang.setBrief(product.getBrief());
                prodLang.setContent(product.getContent());
                prodLang.setProdName(product.getProdName());
                prodLangList.add(prodLang);
                prodLangService.saveBatch(prodLangList);
                // ES 修改
                eventPublisher.publishEvent(new EsProductUpdateEvent(product.getProdId(), null, EsOperationType.UPDATE));
//                if(product.getVirtualProductForm().getAttr() == 4 && product.getVirtualProductForm().getModelType().equals("3")){
//                    eventPublisher.publishEvent(new ZteFileUploadEvent(product.getVirtualProductForm().getAttrData(),product.getProdId(), EsOperationType.UPDATE ));
//                }

                if(!Objects.isNull(product.getMold()) && Objects.equals(product.getMold(), ProdType.PROD_TYPE_SECKILL.value())) {
                    BeanUtil.copyProperties(product.getVirtualProductForm(), synchronizationprodProduct.getVirtualProductForm(),
                            "isPresenter",
                            "dayNum",
                            "monyPreType",
                            "monyPreTypeNum",
                            "monyPreDayNum",
                            "isTransfer",
                            "transferDayNum",
                            "transferPreDayNum");
                    synchronizationprodProduct.getVirtualProductForm().setProdId(product.getProdId());
                    prodNftService.update(synchronizationprodProduct.getVirtualProductForm(),new QueryWrapper<ProdNft>().eq("prod_id",product.getProdId()));
                }
            }
        }
    }


    private boolean matchingProdData(Object product, Object synchronizationprodProduct) {
        Class clazz =synchronizationprodProduct.getClass();
        try {
            // 获取所有字段
            Field[] Fields = clazz.getDeclaredFields();
            for (Field field : Fields) {
                String fieldName=field.getName();// 字段名
                if("prodId".equals(field.getName()) || "serialVersionUID".equals(field.getName()) || "shopId".equals(field.getName()) || "deliveryTemplateId".equals(field.getName()) || "virtualProductForm".equals(fieldName)){
                    continue;
                }
                PropertyDescriptor pd=new PropertyDescriptor(field.getName(),clazz);
                Method getMethod=pd.getReadMethod();
                // 在oldObject上调用get方法等同于获得oldObject的属性值
                Object oldValue = getMethod.invoke(synchronizationprodProduct);
                // 在newObject上调用get方法等同于获得newObject的属性值
                Object newValue = getMethod.invoke(product);

                // 对比两个值是否一致
                if(ObjectUtil.isNotEmpty(oldValue) && ObjectUtil.isNotEmpty(newValue) && !oldValue.equals(newValue)){
//                    Product result=new Product();
//                    result.setField(fieldName);
//                    result.setFieldName(fieldName);
//                    result.setOldValue(oldValue);
//                    result.setNewValue(newValue);
//                    result.setRemark(oldValue+"->"+newValue);
                    return true;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
